package com.my.socket.nio;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Set;
import java.util.concurrent.Callable;

/**
 * User: Alex Zhong
 * Date: 2016/6/17
 */
public class SelectCallable implements Callable<Void> {
    private static final Logger LOGGER = LoggerFactory.getLogger(SelectCallable.class);

    private Selector selector;

    public SelectCallable(Selector selector) {
        this.selector = selector;
    }

    @Override
    public Void call() throws Exception {
        while (true) {
            //当注册的事件到达时，方法返回；否则,该方法会一直阻塞
            selector.select();

            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            for (SelectionKey selectionKey : selectionKeys) {
                selectionKeys.remove(selectionKey);

                if (selectionKey.isAcceptable()) {
                    ServerSocketChannel server = (ServerSocketChannel) selectionKey.channel();
                    SocketChannel socketChannel = server.accept();
                    socketChannel.configureBlocking(false);
                    socketChannel.register(selector, SelectionKey.OP_READ);
                    LOGGER.info("handle a connection from the client {}", socketChannel.getRemoteAddress());
                }

                if (selectionKey.isReadable()) {
                    SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
                    socketChannel.configureBlocking(false);
                    ByteBuffer byteBuffer = ByteBuffer.allocate(15);
                    socketChannel.read(byteBuffer);
                    String message = new String(byteBuffer.array());
                    LOGGER.info("receive the message [{}] from the client {}", message, socketChannel.getRemoteAddress());

                    message = message.toUpperCase();

                    socketChannel.write(ByteBuffer.wrap(message.getBytes()));
                    LOGGER.info("send the message [{}] to the client {}", message, socketChannel.getRemoteAddress());

                    socketChannel.register(selector, SelectionKey.OP_CONNECT);
                }
            }
        }
    }
}
